package net.zdsoft.wpchat.support.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import net.zdsoft.keel.jdbc.JdbcBasicDao;
import net.zdsoft.keel.jdbc.MapRowMapper;
import net.zdsoft.keel.jdbc.MultiRowMapper;
import net.zdsoft.keel.util.Validators;
import net.zdsoft.wpchat.support.dao.GroupPermDao;
import net.zdsoft.wpchat.support.entity.AuthCatalog;
import net.zdsoft.wpchat.support.entity.AuthModule;
import net.zdsoft.wpchat.support.entity.AuthOperation;
import net.zdsoft.wpchat.support.entity.GroupPermission;

import org.springframework.stereotype.Repository;

/**
 * 群组对应权限关系dao实现
 *
 * @author xuan
 */
@Repository
public class GroupPermDaoImpl extends JdbcBasicDao implements GroupPermDao {
	private static final String SQL_FIND_BY_GROUP_ID_IN = "SELECT "
			+ "group_id, auth_operation_id, permission FROM "
			+ "su_group_permission WHERE group_id IN";
	private static final String SQL_DELETE_BY_GROUP_ID_IN = "DELETE FROM "
			+ "su_group_permission WHERE group_id IN";
	private static final String SQL_DELETE_GROUP_PERMISION = "DELETE FROM "
			+ "su_group_permission WHERE group_id=?";
	private static final String SQL_DELETE_GROUP_CATALOG_PERMISION = "DELETE "
			+ "FROM su_group_permission WHERE group_id=? "
			+ "AND auth_operation_id IN "
			+ "(SELECT id FROM su_auth_operation WHERE auth_module_id IN "
			+ "(SELECT id FROM su_auth_module WHERE auth_catalog_id=?))";
	private static final String SQL_INSERT_GROUP_PERMISION = "INSERT INTO "
			+ "su_group_permission (group_id, auth_operation_id, permission) VALUES(?,?,?)";
	private static final String SQL_FIND_ALL_CATALOG = "SELECT id, namespace, display_order, "
			+ "name, state, is_visible FROM su_auth_catalog WHERE EXISTS (SELECT 1 FROM su_auth_module "
			+ "WHERE su_auth_module.auth_catalog_id=su_auth_catalog.id AND EXISTS (SELECT 1 FROM "
			+ "su_auth_operation WHERE su_auth_operation.auth_module_id=su_auth_module.id AND EXISTS "
			+ "(SELECT 1 FROM su_group_permission WHERE "
			+ "su_group_permission.auth_operation_id = su_auth_operation.id AND su_group_permission.group_id "
			+ "IN (SELECT group_id FROM su_group_operator WHERE su_group_operator.operator_id = ?))))";
	private static final String SQL_FIND_ALL_MODULE = "SELECT id, auth_catalog_id, name, type, is_visible, "
			+ "parameter, condition2, display_order, pre_auth_module, state FROM su_auth_module WHERE state=1 "
			+ "AND EXISTS (SELECT 1 FROM su_auth_operation WHERE "
			+ "su_auth_operation.auth_module_id=su_auth_module.id AND EXISTS (SELECT 1 FROM "
			+ "su_group_permission WHERE su_group_permission.auth_operation_id = su_auth_operation.id "
			+ "AND su_group_permission.group_id IN (SELECT group_id FROM su_group_operator "
			+ "WHERE su_group_operator.operator_id = ?)))";
	private static final String SQL_FIND_ALL_OPERATION = "SELECT id, auth_module_id, name, scope, action, "
			+ "state, label FROM su_auth_operation WHERE state=1 AND EXISTS (SELECT 1 FROM su_group_permission "
			+ "WHERE su_group_permission.auth_operation_id = su_auth_operation.id AND su_group_permission.group_id "
			+ "IN (SELECT group_id FROM su_group_operator WHERE su_group_operator.operator_id = ?))";

	@Override
	public void deleteByGroupIds(String... groupIds) {
		if (Validators.isEmpty(groupIds)) {
			return;
		}
		updateForInSQL(SQL_DELETE_BY_GROUP_ID_IN, null, groupIds);
	}

	@Override
	public List<GroupPermission> findByGroupIds(String... groupIds) {
		if (Validators.isEmpty(groupIds)) {
			return Collections.emptyList();
		}
		return queryForInSQL(SQL_FIND_BY_GROUP_ID_IN, null, groupIds,
				new GroupPremMultiRowMapper());
	}

	@Override
	public void deleteGroupPerms(String groupId) {
		if (Validators.isEmpty(groupId)) {
			return;
		}
		update(SQL_DELETE_GROUP_PERMISION, groupId);
	}

	@Override
	public void deleteGroupPerms(String groupId, String catalogId) {
		if (Validators.isEmpty(groupId) || Validators.isEmpty(catalogId)) {
			return;
		}
		update(SQL_DELETE_GROUP_CATALOG_PERMISION, new Object[] { groupId,
				catalogId }, new int[] { Types.CHAR, Types.CHAR });
	}

	@Override
	public void insertGroupPerms(GroupPermission... groupPerms) {
		if (Validators.isEmpty(groupPerms)) {
			return;
		}

		List<Object[]> listOfArgs = new ArrayList<Object[]>();
		for (int i = 0; i < groupPerms.length; i++) {
			Object[] args = { groupPerms[i].getGroupId(),
					groupPerms[i].getAuthOperationId(),
					groupPerms[i].getPermission() };
			listOfArgs.add(args);
		}
		int[] argsTypes = { Types.CHAR, Types.CHAR, Types.INTEGER };
		batchUpdate(SQL_INSERT_GROUP_PERMISION, listOfArgs, argsTypes);
	}

	@Override
	public Map<String, AuthCatalog> findCatalogMap(String operatorId) {
		return queryForMap(SQL_FIND_ALL_CATALOG, new Object[] { operatorId },
				new AuthCatalogMapRowMapper());
	}

	@Override
	public Map<String, AuthModule> findModuleMap(
			Map<String, AuthCatalog> catalogMap, String operatorId) {
		return queryForMap(SQL_FIND_ALL_MODULE, new Object[] { operatorId },
				new AuthModuleMapReader(catalogMap));
	}

	@Override
	public Map<String, AuthOperation> findOperationMap(
			Map<String, AuthModule> moduleMap, String operatorId) {
		return queryForMap(SQL_FIND_ALL_OPERATION, new Object[] { operatorId },
				new AuthOperationMapReader(moduleMap));
	}

	/**
	 * 群组对应操作权限多条结果集
	 *
	 * @author xuan
	 */
	private static class GroupPremMultiRowMapper implements MultiRowMapper<GroupPermission> {
		@Override
		public GroupPermission mapRow(ResultSet rs, int rowNum)
				throws SQLException {
			GroupPermission gp = new GroupPermission();
			gp.setGroupId(rs.getString("group_id"));
			gp.setAuthOperationId(rs.getString("auth_operation_id"));
			gp.setPermission(rs.getInt("permission"));
			return gp;
		}
	}

	/**
	 * 大类目录map结果集
	 *
	 * @author xuan
	 */
	private static class AuthCatalogMapRowMapper implements MapRowMapper<String, AuthCatalog> {
		@Override
		public String mapRowKey(ResultSet rs, int rowNum) throws SQLException {
			return rs.getString("id");
		}

		@Override
		public AuthCatalog mapRowValue(ResultSet rs, int rowNum)
				throws SQLException {
			AuthCatalog catalog = new AuthCatalog();
			catalog.setId(rs.getString("id"));
			catalog.setNamespace(rs.getString("namespace"));
			catalog.setDisplayOrder(rs.getInt("display_order"));
			catalog.setName(rs.getString("name"));
			catalog.setState(rs.getInt("state"));
			catalog.setVisible(1 == rs.getInt("is_visible"));
			return catalog;
		}
	}

	/**
	 * 模块map结果集
	 *
	 * @author xuan
	 */
	private static class AuthModuleMapReader implements MapRowMapper<String, AuthModule> {
		private Map<String, AuthCatalog> catalogMap = null;
		public AuthModuleMapReader(Map<String, AuthCatalog> catalogMap) {
			this.catalogMap = catalogMap;
		}

		@Override
		public String mapRowKey(ResultSet rs, int rowNum) throws SQLException {
			return rs.getString("id");
		}

		@Override
		public AuthModule mapRowValue(ResultSet rs, int rowNum)
				throws SQLException {
			AuthModule module = new AuthModule();

			String catalogId = rs.getString("auth_catalog_id");
			AuthCatalog catalog = catalogMap.get(catalogId);
			if (catalog == null) {
				throw new RuntimeException("Could not find catalog["
						+ catalogId + "]");
			}
			module.setCatalog(catalog);

			module.setId(rs.getString("id"));
			module.setName(rs.getString("name"));
			module.setVisible(1 == rs.getInt("is_visible"));
			module.setDisplayOrder(rs.getInt("display_order"));

			String parameter = rs.getString("parameter");
			module.setParameters(Validators.isEmpty(parameter) ? new String[0]
					: parameter.split(","));

			String condition = rs.getString("condition2");
			module.setConditions(Validators.isEmpty(condition) ? new String[0]
					: condition.split(","));

			String preModule = rs.getString("pre_auth_module");
			module.setPreModules(Validators.isEmpty(preModule) ? new String[0]
					: preModule.split(","));

			module.setState(rs.getInt("state"));
			module.setType(rs.getInt("type"));
			return module;
		}
	}

	/**
	 * 操作权限map结果集
	 *
	 * @author xuan
	 */
	private static class AuthOperationMapReader implements MapRowMapper<String, AuthOperation> {
		private Map<String, AuthModule> moduleMap = null;
		public AuthOperationMapReader(Map<String, AuthModule> moduleMap) {
			this.moduleMap = moduleMap;
		}

		@Override
		public String mapRowKey(ResultSet rs, int rowNum) throws SQLException {
			return rs.getString("id");
		}

		@Override
		public AuthOperation mapRowValue(ResultSet rs, int rowNum)
				throws SQLException {
			AuthOperation operation = new AuthOperation();

			String moduleId = rs.getString("auth_module_id");
			AuthModule module = moduleMap.get(moduleId);
			if (module == null) {
				throw new RuntimeException("Could not find module[" + moduleId
						+ "]");
			}
			operation.setModule(module);

			operation.setId(rs.getString("id"));
			operation.setName(rs.getString("name"));

			String scope = rs.getString("scope");
			operation.setScope(Validators.isEmpty(scope) ? new String[0]
					: scope.split(","));

			String action = rs.getString("action");
			operation.setAction(Validators.isEmpty(action) ? new String[0]
					: action.split(","));

			operation.setState(rs.getInt("state"));
			operation.setLabel(rs.getString("label"));
			return operation;
		}
	}

}
